<?php



namespace Fendx\Router;


use Fendx\Annotation\AutoController;
use Fendx\Annotation\Controller;
use Fendx\Annotation\Mapping;
use Fendx\Annotation\Middleware;
use Fendx\Annotation\Middlewares;

class AnnotationRouterParser
{
    private $config = null;
    private $options = [];
    public function __construct($config) {
        $this->config = $config;
    }


    /**
     * 解析
     *
     */
    public function parse($className, $classMetas, $methodsMetas) {
        // 入口路由前缀
        $rootPrefix = $this->parseRootRoutePrefix($className, $classMetas);
        if (empty($rootPrefix)) {
            return [];
        }

        // 解析类中间件
        $classMiddlewares = $this->parseMiddleware($classMetas);

        // 解析类属性参数
        $classOptions = $this->parseOptions($classMetas);

        $isAutoController = $this->isAutoController($classMetas);

        $result = [];
        foreach ($methodsMetas as $name => $methodMetas) {

            // 解析 method 其它信息
            $methodOther = $this->parseMethodOther($isAutoController, $name, $methodMetas);
            if (empty($methodOther)) {
                continue;
            }

            // 解析方法中间件
            $methodMiddlewares = $this->parseMiddleware($methodMetas);

            // 解析方法属性参数
            $methodOptions = $this->parseOptions($methodMetas);

            $middlewares = $this->merge(...($this->config['middlewares'] ?? []), ...$classMiddlewares, ...$methodMiddlewares);

            $options = $this->merge(...($this->config['options'] ?? []), ...$classOptions, ...$methodOptions);


            $result[] = [
                'route' => sprintf('%s%s', $rootPrefix, $methodOther['route']),
                'handle' => sprintf('%s@%s', $className, $name),
                'httpMethods' => $methodOther['httpMethods'],
                'options' => $options,
                'middlewares' => $middlewares,
            ];

        }

        return $result;
    }

    /**
     * 解析路由前缀
     *
     */
    private function parseRootRoutePrefix($className, $classMetas) {
        // 入口路由前缀
        $rootPrefix = isset($this->config['prefix']) && !empty($this->config['prefix']) ? $this->config['prefix'] : '/';

        // 类里定义的前缀
        $classPrefix = '';
        foreach ($classMetas as $meta) {
            if ($meta instanceof Controller || $meta instanceof  AutoController) {
                $classPrefix = $meta->prefix;
                break;
            }
        }

        // 通过类名获取的名字
        $classRoute = str_replace(substr($this->config['root'], 1), '', $className);
        $classRoute = strtolower(str_replace('\\','/', $classRoute));

        if (empty($classPrefix)) {
            $route = sprintf('%s%s', $rootPrefix, $classRoute);
        } else {
            $route = str_starts_with($classPrefix, '/') ? $classPrefix : sprintf('%s%s', $rootPrefix, $classPrefix);
        }
        return $route;
    }

    /**
     * 解析中间件
     *
     */
    private function parseMiddleware($metas) {
        $middlewares = [];
        foreach ($metas as $meta) {
            if ($meta instanceof Middleware) {
                $middlewares[] = $meta->middleware;
            }
            if ($meta instanceof Middlewares) {
                array_push($middlewares, ...$meta->middlewares);
            }
        }
        return $middlewares;
    }

    /**
     * 解析属性
     */
    private function parseOptions(array $metas) {
        $options = [];
        foreach ($metas as $meta) {
            if ($meta instanceof Mapping
                || $meta instanceof Controller
                || $meta instanceof AutoController
            ) {
                array_push($options, ...$meta->options);
            }
        }
        return $options;
    }

    private function merge(string ...$values) {
        return array_unique(array_filter($values));
    }

    /**
     * 检测是否是自动路由
     */
    private function isAutoController(array $classMetas) {
        $isAutoController = false;
        foreach ($classMetas as $classMeta) {
            if ($classMeta instanceof AutoController) {
                $isAutoController = true;
            }
        }
        return $isAutoController;
    }


    private function parseMethodOther(bool $isAutoController, string $methodName, array $methodMetas) {
        $result = [];
        if ($isAutoController) {
            // 如果是自动路由，则使用 默认配置
            return [
                'httpMethods' => ['GET', 'POST'],
                'route' => sprintf('/%s', $methodName),
            ];
        }
        foreach ($methodMetas as $meta) {
            if ($meta instanceof Mapping) {
                $result['httpMethods'] = $meta->methods ?? ['GET', 'POST'];
                $result['route'] = $meta->path;
            }
        }
        return $result;
    }
}
